mapl.maps = {};

mapl.mapping = {
	g_api_key:{
		'file:///':'',
		'http://localhost:3518/':'',
		'http://fairdev.digitalink.com/':'ABQIAAAAbpEtUslQi1LmK-MGGLZKExRoth-nJbhMsBipS2dzwR72BKq0ShSqjPH7XtvBUqNjiND9gDhROt5C_g',
		'http://wppdev.digitalink.com/':'ABQIAAAAbpEtUslQi1LmK-MGGLZKExT2GI6JOtjghRcS3s-bQtMcTjInwBQehRdZgXhffrWD5RXKXfTGU3f6hw',
		'http://lepdev.digitalink.com/':'ABQIAAAAtFpYFK5giM4tkyQ2_2uRZhRVNhjrnIywCZsgGNRcij93owpwyBQd0V4mjJxemPVgDALXO2EHrm9HKw',
		'http://loudounextra.washingtonpost.com/':'ABQIAAAAtFpYFK5giM4tkyQ2_2uRZhT1lZgjol4o_-tg6T0i_9V0P9kLZBSvVMbm6yh7yES24RczfxkkBfQ2Vw',
		'http://specials.washingtonpost.com/':'ABQIAAAAbpEtUslQi1LmK-MGGLZKExTWbwehQreZWy9_Ax2njNQBUMGhQhQYzmGyA4hFMIQX2DV2k_kqYHIfJQ'
	},
	init:function(){
		window.addEvent('unload',function(){
			try { GUnload() } catch(e){}
		});
		mapl.addDomInit(mapl.mapping.initMaps);
		mapl.mapping.initMaps(document);
	},
	initMaps:function(root){
		root.getElements('.imap').each(function(s){
			var config = new mapl.mapping.map(s);
		});
	},
	map:new Class({
		layers:{},
		config:{
			autopin:1,
			pins:[],
			layers:{},
			lat:39.037078,
			lng:-77.409253,
			uiSize:'Tiny',
			onLoad:null,
			zoomLevel:11,
			icon:'basic',
			icons:[],
			mapTypes:['normal'],
			controlTypes:['small'],
			kmls:[]
		},
		initialize:function(el){
			//setDefault Icons
			this.icons = {
				basic:new this.Icon("http://media.washingtonpost.com/wp-srv/specials/loudoun/css/images/push-pin-small-no-shadow.png",
					"http://www.washingtonpost.com/wp-srv/specials/loudoun/css/images/push-pin-small-shadow.png",
					[40, 31],
					[40, 31],
					[10, 28],
					[10, 28]		
				),
				treeIcon:new this.Icon(
					"http://maps.google.com/mapfiles/ms/micons/tree.png",
					"http://maps.google.com/mapfiles/ms/micons/tree.shadow.png",
					[32, 32],
					[59, 32],
					[12, 25],
					[12, 35]
				),
				wineIcon:new this.Icon(
					"http://www.washingtonpost.com/wp-srv/specials/loudoun/css/images/wine.png",
					"http://www.washingtonpost.com/wp-srv/specials/loudoun/css/images/wine-shadow.png",
					[59, 59],
					[59, 59],
					[12, 25],
					[12, 35]
				)
			};
			
			//aliasing for API dependant map constants
			this.controlTyping = {small:GSmallMapControl,large:GLargeMapControl,smallZoome:GSmallZoomControl,scale:GScaleControl,mapType:GMapTypeControl,menuMapType:GMenuMapTypeControl,hierarchical:GHierarchicalMapTypeControl,overview:GOverviewMapControl}
			this.mapTyping = {defaultMaps:G_DEFAULT_MAP_TYPES,normal:G_NORMAL_MAP,satellite:G_SATELLITE_MAP,physical:G_PHYSICAL_MAP,hybrid:G_HYBRID_MAP,sky:G_SKY_MAP_TYPES,mars:G_MARS_MAP_TYPES,moon:G_MOON_MAP_TYPES,skyVisible:G_SKY_VISIBLE_MAP,marsInfared:G_MARS_INFRARED_MAP,marsVisible:G_MARS_VISIBLE_MAP,marsElevation:G_MARS_ELEVATION_MAP,moonVisible:G_MOON_VISIBLE_MAP,moonElevation:G_MOON_ELEVATION_MAP}
			
			//config and componenets init
			
			//Map config
			if(el.className.test(new RegExp('imap-config','i'))){
				$extend(this.config,JSON.decode('{'+el.className.match(/(?:imap-config\[)(.*)(?:])/i)[1]+'}'));
			}
			
			//Components sniff and config
			el.getElements('.imap-config').each(function(conf){
				$extend(this.config,JSON.decode(conf.get('text')));
			}.bind(this));
			
			el.getElements('.imap-point').each(function(d){
				var pin = null;
				if(d.className.test(new RegExp('imap-point-config','i'))){
					pin = JSON.decode('{'+d.className.match(/(?:imap-point-config\[)(.*)(?:])/i)[1]+'}');
				}
				d.getElements('.imap-point-config').each(function(cd){
					pin = JSON.decode(cd.get('text'));
					cd.destroy();
				});
				pin.info = d.innerHTML;
				this.config.pins.push(pin);
			}.bind(this));
			
			el.getElements('.imap-layer').each(function(s){
				var layer = new this.layer(s.get('text'))
				var id = s.id?s.id:layer.urls[0].href;
				this.config.layers[id] = layer;
			}.bind(this));
			
			// more map init
			var types = [];
			$each(this.config.mapTypes,function(s){
				if(this.mapTyping[s]){
					types.push(this.mapTyping[s]);
				}
			}.bind(this));
			this.config.icon = this.icons[this.config.icon];
			
			//mapping init
			
			this.map = new GMap2(el, {mapTypes: types});
			$each(this.config.controlTypes,function(s){
				if(this.controlTyping[s]){
					this.map.addControl(new this.controlTyping[s]());
				}
			}.bind(this));
			
			this.map.animatePan = true;
			GEvent.addListener(this.map,'load',this.mapReady.pass(el,this));
			this.setCenterZoom([this.config.lat, this.config.lng], this.config.zoomLevel);
		},
		
		mapReady:function(el){
			// register the map
			mapl.maps[el.id] = this;
			el.mapReady = true;
			this.mapId = el.id;
			if(this.config.autopin){
				this.addPin([this.config.lat, this.config.lng]);
			}
			// Set Origin
			this.origin = [this.map.getBounds().getSouthWest().lat(),this.map.getBounds().getSouthWest().lng()];
			//place all pins
			if(this.config.pins.length>0){
				this.clearAllLayers();
				var layer = this.addLayer('default');
				$each(this.config.pins,function(d){
					if(d.lat && d.lng){
						var icon = null;
						if(d.icon){
							icon = new this.Icon(d.icon.image,d.icon.shadow,d.icon.iconSize,d.icon.shadowSize,d.icon.inconAnchor,d.icon.inconWindowAnchor);
						}
						this.addPin([d.lat, d.lng], {layer:layer,info:d.info?d.info:null,icon:icon});
					}
				}.bind(this));
				this.setCenterZoom(layer);
			}
			// open KML
			$each(this.config.kmls,function(s){
				this.map.addOverlay(new GGeoXml(s));
			}.bind(this));
			// layer config
			$each(this.config.layers,function(s){
				for(i=0;i<s.urls.length;i++){
					var overlay = new GGroundOverlay(s.urls[i].href, new GLatLngBounds(
						this.getLL(s.bounds.sw),
						this.getLL(s.bounds.ne)
					));
			        this.map.addOverlay(overlay);
			        s.overlays.push(overlay);
			        
				}
				if(s.overlays.length>1 && s.autostart){
					s.animate();
				}
			}.bind(this));
			if(this.config.onLoad){
				this.config.onLoad();
			}
		},
						
		layer:Class({
			urls:[],
			delay:300,
			bounds:{sw:[],ne:[]},
			overlays:[],
			autoPlay:1,
			frame:-1,
			timmer:null,
			initialize:function(config){
				$extend(this,JSON.decode(config));
			},
			animate:function(){
				this.frame++;
				if(this.frame>=this.overlays.length){
					this.frame = 0;
				}
				this.hide();
				this.show();
				this.cancel();
				this.timmer = setTimeout(this.animate.bind(this),this.delay);
			},
			stop:function(){
				if(this.timmer){clearTimeout(this.timmer)};
			},
			start:function(){
				this.animate();
			},
			hide:function(){
				$each(this.overlays,function(ol){
					ol.hide();
				});
			},
			show:function(){
				this.overlays[this.frame].show();
			}
		}),
		
		CustomInfoWindow:new Class({
			initialize:function(map,pin,node,pane,offset){
				if($type(node)=='string'){
					node = new Element('div').set('html',node);
				}
				
				this.map = map;
				this.offset = offset;
				this.point = pin.getPoint();
				this.node = node;
				this.fx = new Fx.Morph(this.node,{delay:400});
				this.placeListener = GEvent.addListener(this.map, 'zoomend', this.place.bind(this));
				
				this.node.getElements('.imap-custom-info-close').each(function(s){
					s.addEvent('click',this.close.bind(this));
				},this);
				this.node.set('opacity',0);
				this.node.inject(pane);
				this.place()
				this.fx.start({opacity:1});
			},
			place:function(){
				var origin = this.map.fromLatLngToDivPixel(this.point);
				var x = origin.x + this.offset.x;
				var y = origin.y + this.offset.y - this.node.getSize().y;
				this.node.setStyles({top:y,left:x,position:'absolute'});
				this.map.panTo( this.map.fromDivPixelToLatLng( new GPoint( x+this.node.getSize().x/2-20, y+this.node.getSize().y/2 ) ) );
			},
			close:function(node){
				GEvent.removeListener(this.placeListener);
				this.node.destroy();
			}
		}),
		
		Icon:new Class({
				initialize:function(image,shadow,iS,sS,iA,iWA){
					this.image=image;
					this.shadow=shadow;
					this.iconSize=new GSize(iS[0],iS[1]);
					this.shadowSize=new GSize(sS[0], sS[1]);
					this.iconAnchor=new GPoint(iA[0], iA[1]);
					this.infoWindowAnchor=new GPoint(iWA[0], iWA[1]);
				}
		}),
		
		// You can pass in either a Layer, a latlng or both a latlng and a zoom
		setCenterZoom:function(latlng,zoom){
			if(!zoom){
				if($type(latlng) == 'array'){
					this.map.panTo(this.getLL(latlng));
				}else{
					this.map.setZoom(this.map.getBoundsZoomLevel(latlng.bounds));
					this.map.panTo(latlng.bounds.getCenter());
				}
			}else{
				this.map.setCenter(this.getLL(latlng), zoom);
			}
		},
		
		getLL:function(lat,lng){
			if($type(lat) == 'array'){
				var point = new GLatLng(lat[0],lat[1]);
			}else{
				var point = new GLatLng(lat,lng);
			}
			return point;
		},
		
		addCustomInfoWindow:function(pin,node,options){
			if(!options){options = {}};
			if(this.currentCustomWindow && !options.multiWindow){
				this.currentCustomWindow.close();
			}
			var pane = $(this.map.getPane(options.pane?options.pane:G_MAP_FLOAT_PANE));
			this.currentCustomWindow = new this.CustomInfoWindow(this.map,pin,node,pane,{x:options.offsetX?options.offsetX:0,y:options.offsetY?options.offsetY:0});
		},
		
		addLayer:function(name){
			if(!name){
				name = 'default';
			}
			if(!this.layers[name]){
				this.layers[name] = {
					bounds:new GLatLngBounds(),
					overlays:[]
				};
			}
			return this.layers[name];
		},
		
		addPin:function(latlng,options){
			if(!options){
				options = {};
			}
			if(!options.icon){
				options.icon = this.config.icon;
			}
			if($type(options.icon) == 'string'){
				if(this.icons[options.icon]){
					options.icon = this.icons[options.icon];
				}else{
					options.icon = this.config.icon;
				}
			}
			var ll = this.getLL(latlng);
			var pin = new GMarker(ll , {icon:new GIcon(options.icon)})
			if(options.info){
				GEvent.addListener(pin, 'click', function() {
					this.map.openInfoWindow(pin.getPoint(),options.info, options.infoOptions);
				}.bind(this));
			}else if(options.onclick){
				GEvent.addListener(pin, 'click', options.onclick);
			}
			if(options.mouseover){
				GEvent.addListener(pin, 'mouseover', options.mouseover);
			}
			if(options.mouseout){
				GEvent.addListener(pin, 'mouseout', options.mouseout);
			}
			if(options.layer){
				if($type(options.layer) == "string"){
					options.layer = this.layers[options.layer];
				}
			}else{
				options.layer = this.addLayer();
			}
			options.layer.bounds.extend(this.getLL(latlng));
			options.layer.overlays.push(pin);
			this.map.addOverlay(pin);
			return pin;
		},
		
		clearLayer:function(layer){
			if($type(layer) == "string"){
				layer = this.layers[layer];
			}
			$each(layer.overlays,function(s){
				this.map.removeOverlay(s);
			}.bind(this));
			layer.bounds = new GLatLngBounds();
			return layer;
		},
		
		clearAllLayers:function(){
			this.map.clearOverlays();
			this.layers = {};
		},
		
		openInfo:function(latlng,info,opts){
			this.map.openInfoWindow(this.getLL(latlng),info,opts);
		},
		
		addPop:function(pin,text,xOffset,yOffset){
			var xy = this.map.fromLatLngToContainerPixel(pin.getLatLng());
			var tag = new Element('div',{
				'class':'imap-pop',
				styles:{
					position:'absolute',
					visibility:'hidden',
					overflow:'hidden'
				}
			}).set('html',text);
			tag.inject($(this.mapId));
			new Fx.Morph(tag,{duration:300,transition: Fx.Transitions.Cubic.easeOut}).start({
				opacity:[0,1],
				top:[xy.y+yOffset+5,xy.y+yOffset],
				left:[xy.x+xOffset-5,xy.x+xOffset]
			});
			return tag;
		},
		
		clearPops:function(){
			$(this.mapId).getElements('.imap-pop').each(function(s){
				s.destroy();
			});
		},
		
		clusterize:function(mapped,options){
			var maxPins = options.maxPins?options.maxPins:5;
			var mapWidth = this.map.getSize().width;
			var mapHeight = this.map.getSize().height;
			var iconWidth = options.iconWidth?options.iconWidth:35;
			var iconHeight = options.iconHeight?options.iconHeight:35;
			var bounds = this.map.getBounds();
			var maxLat = bounds.getNorthEast().lat();
			var minLat = bounds.getSouthWest().lat();
			var maxLng = bounds.getNorthEast().lng();
			var minLng = bounds.getSouthWest().lng();
			var latRange = maxLat - minLat;
			var lngRange = maxLng - minLng;			
			var gridLatSize = latRange/(mapHeight/iconHeight);
			var gridLngSize = lngRange/(mapWidth/iconWidth);
			matrix = {};
			$each(mapped.pins,function(pin,n){
				var pinGridX = parseInt((pin.lat-this.origin[0])/gridLatSize);
				var pinGridY = parseInt((pin.lng-this.origin[1])/gridLngSize);
				if(!matrix[pinGridX]){
					matrix[pinGridX] = {}
				}
				if(!matrix[pinGridX][pinGridY]){
					matrix[pinGridX][pinGridY] = []
				}
				matrix[pinGridX][pinGridY].push(n)
			}.bind(this));
			$each(matrix,function(row,x){
				$each(row,function(cell,y){
					if(cell.length>maxPins){
						if(!mapped.clusters){
							mapped.clusters = {}
						}
						var clusterId = 'cluster'+x+'o'+y;
						if(!mapped.clusters[clusterId]){
							mapped.clusters[clusterId] = {
								num:0,
								pins:{},
								bounds:new GLatLngBounds()
							};							
						}
						$each(cell,function(s){
							if(!mapped.clusters[clusterId].pins[s]){
								mapped.clusters[clusterId].num++;
								mapped.clusters[clusterId].pins[s] = mapped.pins[s];
								mapped.clusters[clusterId].bounds.extend(this.getLL([mapped.pins[s].lat,mapped.pins[s].lng]));
							}
							delete mapped.pins[s];
						}.bind(this));
					}
				}.bind(this));
			}.bind(this));
			
		},
		
		geocodeAddr:function(addr,callBack){
			if(!this.geocoder){
				this.geocoder = new GClientGeocoder();
			}
			this.geocoder.getLatLng(addr,callBack);
		},
		
		goToAddr:function(addr,zoom){
			this.geocodeAddr(addr,
			function(point){
				this.setCenterZoom([point.lat(),point.lng()],zoom);
			}.bind(this));
		}
		
	})
}

mapl.mapping.g_api_key = mapl.mapping.g_api_key[mapl.server];

new Asset.javascript('http://maps.google.com/maps?file=api&v=2.x&key='+mapl.mapping.g_api_key+'&async=2&callback=mapl.mapping.init');